package com.astruyk.chordophone;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

/**
 * A class responsible for generating a set of chords from an XML list of chord definitions.
 * @author Anton Struyk
 *
 */
public class ChordImporter {
	private static final String CHORD_ELEMENT = "Chord";
	private static final String CHORD_NAME_ATTRIBUTE = "name";
	private static final String VARIANT_ELEMENT = "Variant";
	private static final String VARIANT_NAME_ATTRIBUTE = "name";
    private static final String FINGERING_ELEMENT = "Fingering";
    private static final String FINGERING_COMMON_ATTRIBUTE = "common";
    private static final String FINGERING_NAME_ATTRIBUTE = "name"; 
    
    /**
     * Generates a new list of chords read in from a stream of XML data. The format
     * of the XML must match that of the embedded raw resource.
     */
    public List<Chord> importChords(InputStream inputStream) throws XmlPullParserException, IOException {
    	List<Chord> importedChords = new ArrayList<Chord>();
    	
    	XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    	factory.setNamespaceAware(false);
    	XmlPullParser parser = factory.newPullParser();
    	
    	//Some variables to use when building the chord
    	String chordName = null;
    	String variantName = null;
    	String fingeringName = null;
    	int fingeringCount = 0; //int used when naming unnamed fingerings
    	boolean isCommon = false;
    	int[] fingering;
    	
    	parser.setInput(new InputStreamReader(inputStream));
    	int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
        	if(eventType == XmlPullParser.START_TAG){
        		String currentTag = parser.getName();
        		
        		if(currentTag.equalsIgnoreCase(CHORD_ELEMENT)){
	        		chordName = parser.getAttributeValue(null, CHORD_NAME_ATTRIBUTE);
        		}else if(currentTag.equalsIgnoreCase(VARIANT_ELEMENT)){
        			variantName = parser.getAttributeValue(null, VARIANT_NAME_ATTRIBUTE);
        		}else if(currentTag.equalsIgnoreCase(FINGERING_ELEMENT)){
        			
        			//Get the name of the fingering, or assign a number if there was none provided
        			fingeringName = parser.getAttributeValue(null, FINGERING_NAME_ATTRIBUTE);
        			if(fingeringName == null){
        				fingeringName = "" + fingeringCount++;
        			}
        			
        			//Get whether or not this is a common fingering
        			String isCommonString = parser.getAttributeValue(null, FINGERING_COMMON_ATTRIBUTE);
        			if(isCommonString != null){
        				isCommon = Boolean.parseBoolean(isCommonString);
        			}
        			
        			//Decode the fingering data
        			parser.next();
        			String encodedFingeringString = parser.getText();
	        		fingering = DecodeFingeringString(encodedFingeringString);
	        		        		
	        		//Generate the new chord and add it to the output set
	        		Chord newChord = new Chord(chordName, variantName, fingeringName, isCommon, fingering);
	        		importedChords.add(newChord);
        		}
        	}else if(eventType == XmlPullParser.END_TAG){
        		
        		//Reset the cache values 
        		String currentTag = parser.getName();
        		if(currentTag.equalsIgnoreCase(CHORD_ELEMENT)){
        			chordName = null;
        		}else if(currentTag.equalsIgnoreCase(VARIANT_ELEMENT)){
        			variantName = null;
        			fingeringCount = 0;
        		}else if(currentTag.equalsIgnoreCase(FINGERING_ELEMENT)){
        			fingeringName = null;
        			fingering = null;
        			isCommon = false;
        		}
        	}
        	
        	eventType = parser.next();
        }
        
        return importedChords;
    }
    
    private int[] DecodeFingeringString(String fingeringString){
    	String[] encodedFingering = fingeringString.split(",");
		int[] fingering = new int[encodedFingering.length];
		for(int i = 0; i < encodedFingering.length; i++){
			String currentElement = encodedFingering[i].trim();
			fingering[i] = currentElement.equals("-") ? -1 : Integer.parseInt(currentElement);
		}
		return fingering;
    }
}
